/*
 * pca9685.c
 *
 *  Created on: Oct 5, 2020
 *      Author: Gary
 */
#include "pca9685.h"

/*
 * @brief 写寄存器
 * @param	八位寄存器地址 uint8_t
 * @param	八位寄存器值 uint8_t
 * @retval null
 */
void PCA9685_WriteReg(uint8_t addr, uint8_t data)
{
	HAL_I2C_Mem_Write(&hi2c1, PCA9685_WRITE_ADDR, addr, I2C_MEMADD_SIZE_8BIT, &data, 1, HAL_MAX_DELAY);
}

/*
 * @brief 读寄存器
 * @param	八位寄存器地址 uint8_t
 * @retval 读取的寄存器值 uint8_t
 */
uint8_t PCA9685_ReadReg(uint8_t addr)
{
	uint8_t data;
	HAL_I2C_Mem_Read(&hi2c1, PCA9685_WRITE_ADDR, addr, I2C_MEMADD_SIZE_8BIT, &data, 1, HAL_MAX_DELAY);
	return data;
}

/*
 * @brief 芯片复位
 * @param null
 * @retval null
 */
void PCA9685_Reset(void)
{
	PCA9685_WriteReg(PCA9685_MODE1_REG, 0);
}

/*
 * @brief 芯片复位
 * @param null
 * @retval null
 */
void PCA9685_SetSleep(uint8_t flag)
{
	uint8_t buffer = PCA9685_ReadReg(PCA9685_MODE1_REG);

	//这种算法虽然逻辑繁琐，看似时间复杂度高，实际上它可以在特定情况减少一次IIC通信，能够省下很多时间。
	if(flag && !(buffer & 0x10))
	{
		buffer |= 0x10;
		PCA9685_WriteReg(PCA9685_MODE1_REG, buffer);
	}
	else if(!flag && buffer & 0x10)
	{
		buffer &= 0xef;
		PCA9685_WriteReg(PCA9685_MODE1_REG, buffer);
	}

	//这种算法虽然逻辑简单，时间复杂度低，但是必定会发起一次IIC通信，实际上需要消耗更多的时间。
//	if(flag)
//	{
//		buffer |= 0x10;
//	}
//	else
//	{
//		buffer &= 0xef;
//	}
//	PCA9685_WriteReg(PCA9685_MODE1_REG, buffer);
}

/*
 * @brief 设置PWM频率（周期）
 * @param PWM评率值，单位HZ，类型float
 * @retval null
 */
void PCA9685_SetFreq(float freq)
{
	//XXX
	//校准参数不确定，可能每个芯片不一样。与25M时钟有关
	uint8_t prescale;
//	prescale = 25E6f / 4096 / freq * 0.915 + 0.5;
	prescale = 25E6f / 4096 / freq * 1.042 + 0.5;
	PCA9685_SetSleep(1);
	PCA9685_WriteReg(PCA9685_PRESCALE_REG, prescale);
	PCA9685_SetSleep(0);
	HAL_Delay(10);
}

/*
 * @brief 设置IIC内部地址读写自加
 * @param 是否自加，0地址不自加，非0地址自加，uint8_t
 * @retval null
 */
void PCA9685_SetAI(uint8_t flag)
{
	uint8_t buffer = PCA9685_ReadReg(PCA9685_MODE1_REG);
	if(flag && !(buffer & 0x20))
	{
		buffer |= 0x20;
		PCA9685_WriteReg(PCA9685_MODE1_REG, buffer);
	}
	else if(!flag && buffer & 0x20)
	{
		buffer &= 0xdf;
		PCA9685_WriteReg(PCA9685_MODE1_REG, buffer);
	}
}

/*
 * @brief PCA9685初始化
 * @param 频率，单位Hz，类型float
 * @retval null
 */
void PCA9685_Init(float freq)
{
	PCA9685_SetAI(1);			//设置地址自增
	PCA9685_SetFreq(freq);
}

/*
 * @brief PWM设置
 * @note PWM高电平的时间取决于周期长度*(关闭-开始)/4096
 * @param 通道，共有16个通道	uint8_t
 * @param 设置PWM开启值，通常为0	uint16_t
 * @param 设置PWM关闭值，在上升值为0的情况下，PWM高电平的时间取决于下降沿的值		uint16_t
 * @retval null
 */
void PCA9685_SetPWM(uint8_t channel, uint16_t on, uint16_t off)
{
	uint8_t buffer[4];
	buffer[0] = on;
	buffer[1] = on >> 8;
	buffer[2] = off;
	buffer[3] = off >> 8;
	HAL_I2C_Mem_Write(&hi2c1, PCA9685_WRITE_ADDR, PCA9685_PWM_REG_OFFSET + channel * 4, I2C_MEMADD_SIZE_8BIT, buffer, 4, HAL_MAX_DELAY);
}


//TODO
/*
 * @brief 我不知道这个函数是干什么的，这个库是好早以前写的，让我研究研究
 * @param
 * @param
 * @retval null
 */
void PCA9685_Set(uint8_t channel, float value)
{
	value = value * 400 / 180;
	PCA9685_SetPWM(channel, 0, 100 + value);
}
